81. 用TCP通信模型创建Web服务器
ISS、Apache、Tomcat等服务器软件可以用来创建Web站点,负责接收客户端浏览器的HTTP请求,其基本原理是采用TCP通信模型。
HTTP是应用层协议,它基于TCP协议,它的底层通信原理遵循TCP通信模型,但HTTP还定义了一些其他的Web通信规范。
如HTTP的状态200表示请求成功,返回的HTML语言的文本等。
服务器端Web应用的默认端口是80,也可修改。
82. 利用UDP通信模型创建即时聊天软件
QQ、MSN等聊天工具对安全的要求不高,一般采用UDP通信模型,UDP的通信是点对点的,不存在谁是服务器,谁是客户端,因此UDP的多线程模型就不用主线程来监听请求了,只需要在线程中分别用DatagramPacket通信即可。
可以创建一个发送消息的线程类和接收消息的线程类。发送消息的线程类主要是监听用户的输入,并通过DatagramPacket类的send()方法把数据发给其他的用户;而接收消息的线程类循环调用DatagramPacket类的receive()方法,接收其他用户发来的数据,并打印在屏幕上。
1 | /* |
1 | /* |
1 | /* |
运行上面聊天程序时,需要打开两个应用程序,一个发送消息,可以在另一个上看到消息。
83. 使用Java访问Web站点
网络爬虫软件用于搜索引擎抓取网页,原理就是模拟浏览器挨个去访问Web站点,得到站点网址的映射。
URL又被称为网络地址,它唯一标识了网络上的资源。通过java.net.URL类访问网络资源。
java.net.HttpURLConnetction类是代表HTTP网络连接的类,由URL类的opentConnetion()方法获得HttpURLConnection对象。HttpURLConnetction可以模拟一个浏览器。发出请求时,设置各种请求头参数、请求参数,传输请求数据;收到响应结果时,获得响应头数据getHeaderFields()和响应内容getInputStream()。
1 | URL url = new URL(“http://www.baidu.com”); |
上面得到头部信息:采用Map类型的key-value格式;得到响应信息:调用连接的getInputStream()方法。
84. Java对数据的支持
具体请见Mysql-2.创建与查询
SQL是结构化的查询语言(structured query language),是专门用于和数据库通信的计算机语言。
1)查询
SELETC <列名> FROM <表名/视图>
WHERE <筛选条件> ORDER BY <列名> <ASC/DESC>
2)更改
插入一行:INSERT INTO t_user VALUES (‘zhangsan’, 30, ‘male’);
插入行的一部分:INSERT INTO t_user (name, age) VALUES (‘zhangsan’, 30);
插入某些查询结果到表:INSERT INTO t_user SELECT *;
UPDATE是对行的某些行或列进行更新。
UPDATE t_user SET gender=’famale’ WHERE name=‘zhangsan’;
DELETE删除行
DELETE FROM t_user WHERE name=’zhangsan’;
85. JDBC的工作原理
Mysql驱动程序的jar包,对于普通的Java程序将jar包放在类搜索路径(CLASSPATH)下;对于Java Web程序将jar包放在WEB_INF/lib文件夹中。
JDBC采用一种驱动模式的设计,提供了两套接口:开发者使用的API和数据库厂商使用的SPI,充分地体现了面向接口编程的好处。
开发者无需关系数据库的连接和调用,值需要使用JDK中提供的标准API编程即可。
86. JDBC操作数据库的步骤
Java提供的关于JDBC的操作接口和类,主要在java.sql和javax.sql包下。
1) 加载驱动程序。具体请见Mysql-1.JDBC连接数据库
Class.forName(“数据库驱动的完成类名”); //通过反射得到Class对象
Mysql的驱动类名为com.mysql.fabric.jdbc.FabricMySQLDriver
2) 获取数据库连接
Connection con = DriverManager.getConnection(“数据库地址”, “用户名”, “密码”);
Mysql的数据库地址格式为:jdbc:mysql://localhost:3306/db_bank
3) 要执行的SQL语句
增、删、改:
String sql1 = “INSERT INTO t_student VALUES (?, ?, ?);
查询:
String sql2 = “SELECT * FROM t_student”;
4)创建会话PreparedStatement(预编译会话)
接口PreparedStatement继承了Statement。
PreparedStatement pstat = conn.prepareStatement(sql1);
5)执行SQL语句
增、删、改:具体请见Mysql-3.PreparedStatement接口和CallableStatement接口
pstat.setString(1, student.getName()); //对第1列设置值其中传入的参数是根据类对象的构造函数决定的,如pstat.setString(1, name);
pstat.setInt(2, getAge());
pstat.setString(3, getGender());
int rst1 = pstat.executeUpdate(sql1); //操作了几条数据就返回几
查询:具体请见Mysql-4.ResultSet结果集、获取元数据
ResultSet rst2 = pstat.executeQury(sql2); //返回结果集
while(rst2.next()){ //ResultSet类的next()方法遍历一行
String name = rst2.getString(“name”); //获取第一列(name)属性的值
int age = rst2.getInt(“age”);
String gender = rst2.getString(“gender”);
System.out.println(“名字:” + name + “年龄:” + age + “性别:” + gender);
}
6) 关闭连接
rst1.close(); //先关结果集
rst2.close();
stat.close(); //关闭会话
conn.close(); //关闭连接
87. 如何使用JDBC事务
具体请见Mysql-6.JDBC事务处理。一个逻辑单位被称为事务,必须具备ACID(原子性(atomicity)、一致性(consistency)、隔离性或独立性(isolation)、持久性(durability))4个属性。
原子性:事务必须是原子工作单元,对于数据的修改,要么全部执行,要不全部不执行。
一致性:在事务完成时,必须使所有的数据都保持一致状态。如A银行转账扣款100元,则B银行的账号一定增加100元。
隔离性:并发事务所做的修改必须与其他并发事务所做的修改隔离。如A和B同时为C转账,一定不能同时对C的余额进行修改。
持久性:事务完成后,它对系统的影响是永久的。该修改即使出现致命的系统故障也会一直保持。
事务的结果只能有两种形式:提交和回滚(rollback)。若操作完全成功则提交,产生永久性的修改(JDBC默认自动提交);若操作不完全成功则回滚,恢复到事务开始前的状态。
(1)关闭自动提交事务,连接的自动提交事务属性设置为false。
1 | Connection conn = DriverManager.getConnection(“数据库地址”, “用户名”,”密码”); |
(2)捕获(try…catch)执行代码,如果执行过程顺利则提交;一旦发生异常就回滚(rollback)事务。
1 | try{ |
(3)关闭连接
一般放在finally块中。
1 | finally{ |
88. 如何使用JDBC实现数据访问对象层
DAO(data access object,数据访问对象层)做的主要工作就是把数据包装成对象和把对象拆分成数据。增、删、改、查是DAO实现的基本操作。
1 | public class User { |
1 |
|
89. 如何使用连接池
若操作数据库的程序比较多,频繁地创建数据库和建立连接是非常耗费资源的,因此提出了数据库连接技术。
数据库连接池中装的是数据库的连接(Connection),当需要连接数据库时,只需要从池子中取出即可。当调用Connection.close()方法时,连接就返回到池子,但并没有真正与数据库断开连接。当连接不够时,它会创建一些连接;当连接太多时,会自动关闭一些不必要的连接。
数据库连接池往往作为一个单独的程序模块进行运行,由他来维护这些连接。开发者可以配置它的一些属性,最大活动连接数、最大空闲连接数、连接超时等。它与传统的JDBC提供连接的方式不太一样,必须使用数据源(Data Source)的形式获取连接,数据源对象往往是以JNDI(Java Naming and Directory Interface,Java命名与目录接口)的形式提供给开发者。数据连接池提供商对连接池的实现各不相同,但它们都必须实现javax.sql.DataSource接口,开发者只需要面向这些接口编程就好了。传统JDBC通过驱动管理器(DriverManager)来获取连接;而连接池则需要用数据源(DataSource)来获取。
1)创建JDNI初始化上下文对象
InitialContext cxt = new InitialContext();
2)通过JNDI上下文获取到的数据源
DataSource ds = (DataSource) cxt.lookup(“数据源在JNDI上的路径”);
3)通过数据源获取到对象
Connection conn = ds.getConnection();
90. 如何使用可滚动的结果集
一般来说,使用ResultSet类的next()方法可以迭代地遍历结果集中的所有的行(可理解为上下移动),但有时希望结果集可以前后移动。JDBC从JDBC2.0开始支持可滚动的结果集(ResultS),可以在结果上前后移动,并且可以跳转到结果集中的任何位置。
在创建会话对象的时候进行指定:
PreparedStatement pstat = conn.prepareStatement (sql, type, concurrency);
其中
1)type用来设置是否为可滚动结果集,它为ResultSet的静态变量:
TYPE_FORWARD_ONLY:结果集不能滚动。
TYPE_SCROLL_INSENSITIVE:结果集可以滚动,但对数据库变化不敏感,数据库查询生成结果集后发生了变化,结果集不发生变化。
TYPE_SCROLL_SENSITIVE:结果集可以滚动,但对数据库变化敏感。
2)concurrency用于指定是否为可更新的结果集,它也为ResultSet的静态变量。
直接在查询结果里修改数据,并同步到数据库。
CONCUR_READ_ONLY:结果集不能用于更新数据库。
CONCUR_UPDATABLE:结果集可以用于更新数据库。
实际上,数据库驱动可能无法支持可滚动或可更新结果集的请求。通过DatabaseMetaData类中的boolean SupportsResultSetType(int type)和boolean SupportsResultSetConcurrency(int type, int concurrency)可以知道某个数据库究竟支持哪些结果集类型以及那些模式。